#include "lxz_config.h"

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

#include "lxz_types.h"
#include "os_port.h"
#include "lxz_runlog.h"
#include "lxz_sysloger.h"
#include "lxz_debug.h"
#include "lxz_ring.h"
#include "lxz_string.h"
#include "lxz_dstring.h"
#include "lxz_atc_req.h"
#include "lxz_atc_rsp.h"
#include "lxz_dbg_vmem.h"

/*
 *  Description:
 *    A structure for describing error-information.
 */
typedef struct _lxzat_rsp_info_t
{
    sint32 it_rsp_code;
    uint08 * pt_rsp_brief;
    uint08 * pt_rsp_detail;
} lxzat_rsp_info_t;

/*
 *  Description:
 *    A unified header for error-information.
 */
#define LXZAT_ERR_INFO_HEADER "+CME ERROR: "
#define LXZAT_ERR_INFO_HEADER_SGCC "ERROR: "

static const lxzat_rsp_info_t * lxzat_lei_f_get(sint32 i_index_id);
static sint32 lxzat_rsp_f_success(lxzat_spcfg_t * p_cur_spcfg, sint32 i_err_code);
static sint32 lxzat_rsp_f_elec_failure(lxzat_spcfg_t * p_cur_spcfg, sint32 i_err_code);
static sint32 lxzat_rsp_f_general_failure(lxzat_spcfg_t * p_cur_spcfg, sint32 i_err_code);

/*
 *  Description:
 *    A table including all error information.
 *  Note: (To Be Extended)
 */
static const lxzat_rsp_info_t gs_lei_table[] =
{
    {E_LEC_ERR_PHONE_FAILURE, "Phone failure", "Phone failure"},
    {E_LEC_ERR_NO_CONNECTION, "NO CONNECTION", "NO CONNECTION"},
    {E_LEC_ERR_PHONE_ADAPTOR_RESERVED, "Adaptor reserved", "Phone adaptor link reserved"},
    {E_LEC_ERR_OPERATION_NOT_ALLOWED, "NOT allowed", "Operation not allowed"},
    {E_LEC_ERR_OPERATION_NOT_SUPPORTED, "NOT supported", "Operation not supported"},
    {E_LEC_ERR_PH_SIM_PIN_REQUIRED, "PH-SIM PIN", "PH-SIM PIN"},
    {E_LEC_ERR_PH_FSIM_PIN_REQUIRED, "PH-FSIM PIN", "PH-FSIM PIN"},
    {E_LEC_ERR_PH_FSIM_PUK_REQUIRED, "PH-FSIM PUK", "PH-FSIM PUK"},
    {E_LEC_ERR_SIM_NOT_INSERTED, "SIM not inserted", "SIM not inserted"},
    {E_LEC_ERR_SIM_PIN_REQUIRED, "SIM PIN", "SIM PIN"},
    {E_LEC_ERR_SIM_PUK_REQUIRED, "SIM PUK", "SIM PUK"},
    {E_LEC_ERR_SIM_FAILURE, "SIM FAILURE", "SIM FAILURE"},
    {E_LEC_ERR_SIM_BUSY, "SIM BUSY", "SIM BUSY"},
    {E_LEC_ERR_SIM_WRONG, "SIM WRONG", "SIM WRONG"},
    {E_LEC_ERR_SIM_PASSWORD, "SIM PASSWD", "SIM PASSWORD"},
    {E_LEC_ERR_SIM_PIN2_REQUIRED, "SIM PIN2", "SIM PIN2"},
    {E_LEC_ERR_SIM_PUK2_REQUIRED, "SIM PUK2", "SIM PUK2"},

    {E_LEC_ERR_NOK, "General Error", "General Error"},
    {E_LEC_ERR_UNSUPPORTED, "Unsupported", "Unsupported"},
    {E_LEC_ERR_NOT_ALLOWED, "Not Allowed", "Not Allowed"},
    {E_LEC_ERR_AT_PREFIX, "No AT Prefix", "No AT Prefix"},
    {E_LEC_ERR_MEM_ADDRESS, "Memory address", "Memory address"},

    {E_LEC_ERR_P_OTHER, "Param Error", "Parameter Error"},
    {E_LEC_ERR_P_TYPE, "Param Type Error", "Parameter Type Error"},
    {E_LEC_ERR_P_TOO_BIG, "Param Too Big", "Parameter Too Big"},
    {E_LEC_ERR_P_TOO_TINY, "Param Too Tiny", "Parameter Too Tiny"},
    {E_LEC_ERR_P_TOO_SHORT, "Param Too Short", "Parameter Too Short"},
    {E_LEC_ERR_P_TOO_LONG, "Param Too Long", "Parameter Too Long"},
    {E_LEC_ERR_P_NB_PARAM, "Param Number", "Parameter Number"},

    {E_LEC_ERR_PDP_OTHER, "PDP Not Active", "PDP Not Active"},
    {E_LEC_ERR_SIM_OTHER, "SIM Error", "SIM Card Error"},
    {E_LEC_ERR_NET_OTHER, "Net Error", "Net Work Error"},
    {E_LEC_ERR_MEM_OTHER, "Mem Error", "Memory Error"},
    {E_LEC_ERR_MEM_MALLOC, "Malloc Error", "Malloc Error"},
    {E_LEC_ERR_MEM_NOT_ENOUGH, "Mem Not Enough", "Memory Not Enough"},

    {E_LEC_ERR_FILE_OTHER, "Unknown Error", "Unknown Error"},
    {E_LEC_ERR_FILE_OPEN_FAILURE, "Open Error", "Open Error"},
    {E_LEC_ERR_FILE_READ_FAILURE, "Read Error", "Read Error"},
    {E_LEC_ERR_FILE_SEEK_FAILURE, "Seek error", "Seek error"},
    {E_LEC_ERR_FILE_WRITE_FAILURE, "Write error", "Write error"},
    {E_LEC_ERR_FILE_CLOSE_FAILURE, "Close error", "Close error"},
    {E_LEC_ERR_FILE_NOT_EXIST, "Not exist", "File not exist"},

    {E_LEC_SGCC_STATUS, "Unknown Error", "Unknown Error"},
    {E_LEC_SGCC_PDP_ACTIVE_REJECT, "PDP Active Reject", "PDP Active Reject"},
    {E_LEC_SGCC_PDP_NO_ACTIVED, "PDP Not Active", "PDP Not Active"},
    {E_LEC_SGCC_PDP_ACTIVED, "PDP Active", "PDP Active"},
    {E_LEC_SGCC_TCP_CONNECT_REJECT, "TCP Reject", "TCP Reject"},
    {E_LEC_SGCC_TCP_CONNECT_TIMEOUT, "TCP Timeout", "TCP Timeout"},
    {E_LEC_SGCC_SOCKET_CONNECT, "Socket Connect", "Socket Connect"},
    {E_LEC_SGCC_SOCKET_NO_CONNECT, "Socket No Connect", "Socket No Connect"},
    {E_LEC_SGCC_SOCKET_BUFFER_FULL, "Socket Buffer Full", "Socket Buffer Full"},
    {E_LEC_SGCC_SEND_DATA_TIMEOUT, "Send Data Timeout", "Send Data Timeout"},
    {E_LEC_SGCC_DNS_NOT_FOUND, "DNS Not Found", "DNS Not Found"},
    {E_LEC_SGCC_DNS_TIMEOUT, "DNS Timeout", "DNS Timeout"},
    {E_LEC_SGCC_DNS_UNKNOWN, "DNS Unknown", "DNS Unknown"},
    {E_LEC_SGCC_PARAM_NOT_CORRECT, "Param Not Correct", "Param Not Correct"},
    {E_LEC_SGCC_UNKNOWN, "Unknown", "Unknown"},

    {0, NULL, NULL}
};

/*
 *  Description:
 *    Get the description according to the index.
 *  Param: i_index_id, the specified index;
 *  Return: NULL, fail; NON-NULL, success.
 *  History:
 */
static const lxzat_rsp_info_t * lxzat_lei_f_get(sint32 i_index_id)
{
    sint32 i_rsp_num = 0;
    
    i_rsp_num = sizeof(gs_lei_table)/sizeof(gs_lei_table[0]);
    if (i_index_id < i_rsp_num)
    {
        return &(gs_lei_table[i_index_id]);
    }
    
    return NULL;
}

/*
 *  Description:
 *    Output the response according to the error code(only for success).
 *  Param: p_cur_spcfg, the context of current serial-port;
 *  Param: i_err_code, error code;
 *  Return: i_op_status, 0, fail; 1, success.
 *  History:
 */
static sint32 lxzat_rsp_f_success(lxzat_spcfg_t * p_cur_spcfg, sint32 i_err_code)
{
    sint32 i_op_status = 0;

    switch (i_err_code)
    {
    case E_LEC_OK:
        {
            lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "OK");
            break;
        }
    case E_LEC_OK_NOTHING:
        {
            break;
        }
    case E_LEC_OK_CHAR_0x3E:
        {
            lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N0, ">");
            break;
        }
    case E_LEC_OK_CONNECT:
        {
            lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "CONNECT");
            break;
        }
    default:
        {
            break;
        }
    }

    i_op_status = 1;
    return i_op_status;
}

/*
 *  Description:
 *    Output the response according to the error code(State-Grid(only for china)).
 *  Param: p_cur_spcfg, the context of current serial-port;
 *  Param: i_err_code, error code;
 *  Return: i_op_status, 0, fail; 1, success.
 *  History:
 */
static sint32 lxzat_rsp_f_elec_failure(lxzat_spcfg_t * p_cur_spcfg, sint32 i_err_code)
{
    sint32 i_op_status = 0;
    
    sint32 i = 0;
    lxzat_rsp_info_t * p_cur_rspinfo = NULL;
    
    if (p_cur_spcfg == NULL)
    {
        return i_op_status;
    }

    if (i_err_code == E_LEC_SGCC_ERROR)
    {
        lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s", "ERROR");
        return i_op_status;
    }
    
    p_cur_rspinfo = (lxzat_rsp_info_t *)lxzat_lei_f_get(i);
    while (p_cur_rspinfo != NULL)
    {
        if (  (p_cur_rspinfo->it_rsp_code == i_err_code)
            &&(p_cur_rspinfo->pt_rsp_brief != NULL)
            &&(p_cur_rspinfo->pt_rsp_detail != NULL))
        {
            break;
        }
        
        i++;
        p_cur_rspinfo = (lxzat_rsp_info_t *)lxzat_lei_f_get(i);
    }
    
    if (  (p_cur_rspinfo != NULL)
        &&(p_cur_rspinfo->it_rsp_code == i_err_code)
        &&(p_cur_rspinfo->pt_rsp_brief != NULL)
        &&(p_cur_rspinfo->pt_rsp_detail != NULL))
    {
        switch (p_cur_spcfg->pt_nv_cfg->i_cmee_reg)
        {
        case LXZAT_CMEE_MODE_CODE:
        case LXZAT_CMEE_MODE_BRIEF:
        case LXZAT_CMEE_MODE_DETAIL:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s%d", LXZAT_ERR_INFO_HEADER_SGCC, (i_err_code - E_LEC_SGCC_STATUS));
                break;
            }
        default:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%sUnknown error", LXZAT_ERR_INFO_HEADER_SGCC);
                break;
            }
        }
    }
    else
    {
        switch (p_cur_spcfg->pt_nv_cfg->i_cmee_reg)
        {
        case LXZAT_CMEE_MODE_CODE:
        case LXZAT_CMEE_MODE_BRIEF:
        case LXZAT_CMEE_MODE_DETAIL:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s%d", LXZAT_ERR_INFO_HEADER_SGCC, (i_err_code - E_LEC_SGCC_STATUS));
                break;
            }
        default:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%sUnknown error", LXZAT_ERR_INFO_HEADER_SGCC);
                break;
            }
        }
    }

    return i_op_status;
}

/*
 *  Description:
 *    Output the response according to the error code(only for failure).
 *  Param: p_cur_spcfg, the context of current serial-port;
 *  Param: i_err_code, error code;
 *  Return: i_op_status, 0, fail; 1, success.
 *  History:
 */
static sint32 lxzat_rsp_f_general_failure(lxzat_spcfg_t * p_cur_spcfg, sint32 i_err_code)
{
    sint32 i_op_status = 0;
    
    sint32 i = 0;
    lxzat_rsp_info_t * p_cur_rspinfo = NULL;
    
    if (p_cur_spcfg == NULL)
    {
        return i_op_status;
    }
    
    p_cur_rspinfo = (lxzat_rsp_info_t *)lxzat_lei_f_get(i);
    while (p_cur_rspinfo != NULL)
    {
        if (  (p_cur_rspinfo->it_rsp_code == i_err_code)
            &&(p_cur_rspinfo->pt_rsp_brief != NULL)
            &&(p_cur_rspinfo->pt_rsp_detail != NULL))
        {
            break;
        }
        
        i++;
        p_cur_rspinfo = (lxzat_rsp_info_t *)lxzat_lei_f_get(i);
    }
    
    if (  (p_cur_rspinfo != NULL)
        &&(p_cur_rspinfo->it_rsp_code == i_err_code)
        &&(p_cur_rspinfo->pt_rsp_brief != NULL)
        &&(p_cur_rspinfo->pt_rsp_detail != NULL))
    {
        switch (p_cur_spcfg->pt_nv_cfg->i_cmee_reg)
        {
        case LXZAT_CMEE_MODE_CODE:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s%d", LXZAT_ERR_INFO_HEADER, i_err_code);
                break;
            }
        case LXZAT_CMEE_MODE_BRIEF:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s%s", LXZAT_ERR_INFO_HEADER, p_cur_rspinfo->pt_rsp_brief);
                break;
            }
        case LXZAT_CMEE_MODE_DETAIL:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s%s", LXZAT_ERR_INFO_HEADER, p_cur_rspinfo->pt_rsp_detail);
                break;
            }
        default:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%sUnknown error", LXZAT_ERR_INFO_HEADER);
                break;
            }
        }
    }
    else
    {
        switch (p_cur_spcfg->pt_nv_cfg->i_cmee_reg)
        {
        case LXZAT_CMEE_MODE_CODE:
        case LXZAT_CMEE_MODE_BRIEF:
        case LXZAT_CMEE_MODE_DETAIL:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%s%d", LXZAT_ERR_INFO_HEADER, i_err_code);
                break;
            }
        default:
            {
                lxzat_rsp_f_printf(p_cur_spcfg->i_vsp_id, LXZAT_RSP_MODE_P1N1, "%sUnknown error", LXZAT_ERR_INFO_HEADER);
                break;
            }
        }
    }

    return i_op_status;
}

/*
 *  Description:
 *    Output the response according to the error code.
 *  Param: p_cur_spcfg, the context of current serial-port;
 *  Param: i_err_code, error code;
 *  Return: i_op_status, 0, fail; 1, success.
 *  History:
 */
sint32 lxzat_rsp_f_response(lxzat_spcfg_t * p_cur_spcfg, sint32 i_err_code)
{
    sint32 i_op_status = 0;

    sint32 i = 0;
    lxzat_rsp_info_t * p_cur_rspinfo = NULL;

    if (p_cur_spcfg == NULL)
    {
        return i_op_status;
    }
    
    switch (i_err_code & 0x7FFF0000)
    {
    case E_LEC_OK:
        {
            i_op_status = lxzat_rsp_f_success(p_cur_spcfg, i_err_code);
            break;
        }
    case E_LEC_SGCC_STATUS:
        {
            i_op_status = lxzat_rsp_f_elec_failure(p_cur_spcfg, i_err_code);
            break;
        }
    default:
        {
            i_op_status = lxzat_rsp_f_general_failure(p_cur_spcfg, i_err_code);
            break;
        }
    }
    
    return i_op_status;
}

/*
 *  Description:
 *    format string and then write to the specified file.
 *  Param: i_vsp_id, the ID of serial-port;
 *  Param: i_rsp_fmt, the format of current response;
 *  Param: vfmt, the format of stirng;
 *
 * NOTE: 1023 bytes is the maximum length can be supported
 */
sint32 lxzat_rsp_f_printf(sint32 i_vsp_id, sint32 i_rsp_fmt, const char * vfmt, ...)
{
    sint32 i = 0;

    sint32 i_pre_len = 0;
    sint32 i_str_len = 0;
    sint32 i_suf_len = 0;
    sint32 i_sum_len = 0;
    sint32 i_cnt_redo = 0;
    sint32 i_cur_fmt = 0;
    lxzat_spcfg_t * p_cur_spcfg = NULL;
    
    char llbuf[1024];
    va_list ap;


    memset(llbuf, 0x00, sizeof(llbuf));
    p_cur_spcfg = lxzat_spcomm_f_get(i_vsp_id);
    if (p_cur_spcfg != NULL)
    {
        i_cur_fmt = i_rsp_fmt;
        if (i_cur_fmt == LXZAT_RSP_MODE_MASK)
        {
            i_cur_fmt = p_cur_spcfg->i_resp_format;
        }

        i = 0;
        i_cnt_redo = (i_cur_fmt & 0xFF00) >> 8;
        while (i < i_cnt_redo)
        {
			sprintf(&(llbuf[2 * i]), "\r\n");
            i++;
        }

		i_pre_len = 2 * i_cnt_redo;
		va_start(ap,vfmt);
		i_str_len = vsprintf(&(llbuf[i_pre_len]), vfmt, ap);
		va_end(ap);

        i = 0;
		i_cnt_redo = (i_cur_fmt & 0x00FF);
		while (i < i_cnt_redo)
		{
			sprintf(&(llbuf[2 * i + i_pre_len + i_str_len]), "\r\n");
            i++;
		}

		i_suf_len = 2 * i_cnt_redo;
		i_sum_len = i_pre_len + i_str_len + i_suf_len;
		lxzat_spcomm_f_writebyid(i_vsp_id, llbuf, i_sum_len);

#ifdef LXZAT_DEBUG
        lxzpcap_sysloger_printf("%s", llbuf);

        if (i_str_len > 0)
        {
            sint32 i_all_print = 1;
			sint32 i_max_len = 100;

            i = 0;
            while (i < i_str_len)
            {
                if (0 == isprint(llbuf[i + i_pre_len]))
                {
					if (('\r' != llbuf[i + i_pre_len]) && ('\n' != llbuf[i + i_pre_len]))
					{
					    i_all_print = 0;
					    break;
					}
                }

                i++;
            }

            if (i_all_print)
            {
                llbuf[i_pre_len+i_str_len] = '\0';
                OS_DBG_LOG(("lxzat:ATCommand-resp:%s\r\n", &(llbuf[i_pre_len])));
            }
            else
            {
                OS_DBG_LOG(("lxzat:ATCommand-resp: Hex Type\r\n"));
                if (i_str_len < i_max_len)
                {
                    i_max_len = i_str_len;
                }
                OS_DBG_HEX((&(llbuf[i_pre_len]), i_max_len));
            }
        }
#endif /* LXZAT_DEBUG */
    }

    return i_sum_len;
}

/*
 *  Description:
 *    format string and then write to the specified file.
 *  Param: i_vsp_id, the ID of serial-port;
 *  Param: i_urc_flag, the flag of URC status;
 *  Param: i_rsp_fmt, the format of current response;
 *  Param: vfmt, the format of stirng;
 *
 * NOTE: 1023 bytes is the maximum length can be supported
 */
uint32 lxzat_urc_f_printf(sint32 i_vsp_id, sint32 i_rsp_fmt, const char * vfmt, ...)
{
    sint32 i = 0;
    
    sint32 i_pre_len = 0;
    sint32 i_str_len = 0;
    sint32 i_suf_len = 0;
    sint32 i_sum_len = 0;
    sint32 i_cnt_redo = 0;
    sint32 i_cur_fmt = 0;
    lxzat_spcfg_t * p_cur_spcfg = NULL;
    
    char llbuf[1024];
    va_list ap;

    memset(llbuf, 0x00, sizeof(llbuf));
    p_cur_spcfg = lxzat_spcomm_f_get(i_vsp_id);
    if (p_cur_spcfg != NULL)
    {
        i_cur_fmt = i_rsp_fmt;
        if (i_cur_fmt == LXZAT_RSP_MODE_MASK)
        {
            i_cur_fmt = p_cur_spcfg->i_resp_format;
        }
        
        i = 0;
        i_cnt_redo = (i_cur_fmt & 0xFF00) >> 8;
        while (i < i_cnt_redo)
        {
            sprintf(&(llbuf[2 * i]), "\r\n");
            i++;
        }
        
        i_pre_len = 2 * i_cnt_redo;
        va_start(ap,vfmt);
        i_str_len = vsprintf(&(llbuf[i_pre_len]), vfmt, ap);
        va_end(ap);
        
        i = 0;
        i_cnt_redo = (i_cur_fmt & 0x00FF);
        while (i < i_cnt_redo)
        {
            sprintf(&(llbuf[2 * i + i_pre_len + i_str_len]), "\r\n");
            i++;
        }
        
        i_suf_len = 2 * i_cnt_redo;
        i_sum_len = i_pre_len + i_str_len + i_suf_len;
        lxz_ring_f_write(p_cur_spcfg->pt_urc_cache, llbuf, i_sum_len);

#ifdef LXZAT_DEBUG
        if (i_str_len > 0)
        {
            llbuf[i_pre_len+i_str_len] = '\0';
            OS_DBG_LOG(("lxzat:ATCommand-urc:%s\r\n", &(llbuf[i_pre_len])));
            lxzpcap_sysloger_printf("\r\n%s\r\n", &(llbuf[i_pre_len]));
        }
#endif /* LXZAT_DEBUG */
    }
    
    return i_sum_len;
}

/*
 *  Description:
 *    format string and then write to the specified file.
 *  Param: i_vsp_id, the ID of serial-port;
 *  Param: i_rsp_fmt, the format of current response;
 *  Param: vbuf, a data buffer;
 *  Param: ilen, the length of data that stored in vbuf;
 */
sint32 lxzat_rsp_f_printfhex(sint32 i_vsp_id, sint32 i_rsp_fmt, const char * vbuf, sint32 ilen)
{
    sint32 i = 0;

    sint32 i_pre_len = 0;
    sint32 i_str_len = 0;
    sint32 i_suf_len = 0;
    sint32 i_sum_len = 0;
    sint32 i_cnt_redo = 0;
    sint32 i_cur_fmt = 0;
    lxzat_spcfg_t * p_cur_spcfg = NULL;
    
    char * pbuf = (char *)vbuf;
    sint32 i_unit_size = 64;
    char lhexbuf[192]; /* 192 == 3 * i_unit_size*/


    p_cur_spcfg = lxzat_spcomm_f_get(i_vsp_id);
    if (p_cur_spcfg != NULL)
    {
        i_cur_fmt = i_rsp_fmt;
        if (i_cur_fmt == LXZAT_RSP_MODE_MASK)
        {
            i_cur_fmt = p_cur_spcfg->i_resp_format;
        }

        /* Before HEX string, add "\r\n" */
        memset(lhexbuf, 0x00, sizeof(lhexbuf));
        i = 0;
        i_cnt_redo = (i_cur_fmt & 0xFF00) >> 8;
        while (i < i_cnt_redo)
        {
			sprintf(&(lhexbuf[2 * i]), "\r\n");
            i++;
        }

        i_pre_len = 2 * i_cnt_redo;
        lxzat_spcomm_f_writebyid(i_vsp_id, lhexbuf, i_pre_len);

        /* HEX string, output 128 bytes at a time */
        while (ilen >= i_unit_size)
        {
            memset(lhexbuf, 0, sizeof(lhexbuf));
            
            i = 0;
            while (i < i_unit_size)
            {
                sprintf(&(lhexbuf[2 * i]), "%02X", pbuf[i]);
                i++;
            }

            lxzat_spcomm_f_writebyid(i_vsp_id, lhexbuf, (2 * i_unit_size));

            ilen = ilen - i_unit_size;
            pbuf = pbuf + i_unit_size;
        }
        
        if (ilen>0)
        {
            memset(lhexbuf, 0, sizeof(lhexbuf));
        
            i = 0;
            while (i < ilen)
            {
                sprintf(&(lhexbuf[2 * i]), "%02X", pbuf[i]);
                i++;
            }

            lxzat_spcomm_f_writebyid(i_vsp_id, lhexbuf, (2 * ilen));

            pbuf = pbuf + ilen;
            ilen = 0;
        }

        /* After HEX string, add "\r\n" */
        memset(lhexbuf, 0x00, sizeof(lhexbuf));
        i = 0;
		i_cnt_redo = (i_cur_fmt & 0x00FF);
		while (i < i_cnt_redo)
		{
			sprintf(&(lhexbuf[2 * i]), "\r\n");
            i++;
		}

		i_suf_len = 2 * i_cnt_redo;
		lxzat_spcomm_f_writebyid(i_vsp_id, lhexbuf, i_suf_len);

		i_sum_len = i_pre_len + (2 * ilen) + i_suf_len;
    }

    return i_sum_len;
}

/*
 *  Description:
 *    format string and then write to the specified file.
 *  Param: i_vsp_id, the ID of serial-port;
 *  Param: i_rsp_fmt, the format of current response;
 *  Param: vbuf, a data buffer;
 *  Param: ilen, the length of data that stored in vbuf;
 */
sint32 lxzat_rsp_f_printfbin(sint32 i_vsp_id, sint32 i_rsp_fmt, const char * vbuf, sint32 ilen)
{
    sint32 i = 0;

    sint32 i_pre_len = 0;
    sint32 i_str_len = 0;
    sint32 i_suf_len = 0;
    sint32 i_sum_len = 0;
    sint32 i_cnt_redo = 0;
    sint32 i_cur_fmt = 0;
    lxzat_spcfg_t * p_cur_spcfg = NULL;
    
    char * pbuf = (char *)vbuf;
    sint32 i_unit_size = 64;
    char lbinbuf[192]; /* 192 == 3 * i_unit_size*/

    p_cur_spcfg = lxzat_spcomm_f_get(i_vsp_id);
    if (p_cur_spcfg != NULL)
    {
        i_cur_fmt = i_rsp_fmt;
        if (i_cur_fmt == LXZAT_RSP_MODE_MASK)
        {
            i_cur_fmt = p_cur_spcfg->i_resp_format;
        }

        /* Before BIN string, add "\r\n" */
        memset(lbinbuf, 0x00, sizeof(lbinbuf));
        i = 0;
        i_cnt_redo = (i_cur_fmt & 0xFF00) >> 8;
        while (i < i_cnt_redo)
        {
			sprintf(&(lbinbuf[2 * i]), "\r\n");
            i++;
        }

        i_pre_len = 2 * i_cnt_redo;
        lxzat_spcomm_f_writebyid(i_vsp_id, lbinbuf, i_pre_len);

        /* HEX string, output 64 bytes at a time */
        while (ilen >= i_unit_size)
        {
            memset(lbinbuf, 0, sizeof(lbinbuf));
            memcpy(&(lbinbuf[0]), &(pbuf[0]), i_unit_size);

            lxzat_spcomm_f_writebyid(i_vsp_id, lbinbuf, i_unit_size);

            ilen = ilen - i_unit_size;
            pbuf = pbuf + i_unit_size;
        }

        if (ilen>0)
        {
            memset(lbinbuf, 0, sizeof(lbinbuf));
            memcpy(&(lbinbuf[0]), &(pbuf[0]), ilen);
            
            lxzat_spcomm_f_writebyid(i_vsp_id, lbinbuf, ilen);

            pbuf = pbuf + ilen;
            ilen = 0;
        }

        /* After BIN string, add "\r\n" */
        memset(lbinbuf, 0x00, sizeof(lbinbuf));
        i = 0;
		i_cnt_redo = (i_cur_fmt & 0x00FF);
		while (i < i_cnt_redo)
		{
			sprintf(&(lbinbuf[2 * i]), "\r\n");
            i++;
		}

		i_suf_len = 2 * i_cnt_redo;
		lxzat_spcomm_f_writebyid(i_vsp_id, lbinbuf, i_suf_len);

        i_sum_len = i_pre_len + ilen + i_suf_len;
    }

    return i_sum_len;
}

/*
 *  Description:
 *    format string and then write to the specified file.
 *  Param: i_vsp_id, the ID of serial-port;
 *  Param: i_rsp_fmt, the format of current response;
 *  Param: vfmt, the format of stirng;
 *
 * NOTE: 1023 bytes is the maximum length can be supported
 */
sint32 lxzat_dbg_printf(sint32 i_vsp_id, sint32 i_rsp_fmt, const char * vfmt, ...)
{
    sint32 i = 0;
    
    sint32 i_pre_len = 0;
    sint32 i_str_len = 0;
    sint32 i_suf_len = 0;
    sint32 i_sum_len = 0;
    sint32 i_cnt_redo = 0;
    sint32 i_cur_fmt = 0;
    lxzat_spcfg_t * p_cur_spcfg = NULL;

    sint32 i_cur_year = 0;
    sint32 i_cur_mon = 0;
    sint32 i_cur_day = 0;
    sint32 i_cur_hour = 0;
    sint32 i_cur_min = 0;
    sint32 i_cur_sec = 0;
    sint32 i_time_len = 0;
    struct tm* p_tm_ctxt = NULL;
    time_t t_systime_ctxt;
    
    char llbuf[1024];
    va_list ap;

    memset(llbuf, 0x00, sizeof(llbuf));
    p_cur_spcfg = lxzat_spcomm_f_get(i_vsp_id);
    if (p_cur_spcfg != NULL)
    {
        i_cur_fmt = i_rsp_fmt;
        if (i_cur_fmt == LXZAT_RSP_MODE_MASK)
        {
            i_cur_fmt = p_cur_spcfg->i_resp_format;
        }
        
        i = 0;
        i_cnt_redo = (i_cur_fmt & 0xFF00) >> 8;
        while (i < i_cnt_redo)
        {
            sprintf(&(llbuf[2 * i]), "\r\n");
            i++;
        }

        i_pre_len = 2 * i_cnt_redo;
        lxzat_spcomm_f_writebyid(i_vsp_id, llbuf, i_pre_len);

        time(&t_systime_ctxt);
        p_tm_ctxt = gmtime(&t_systime_ctxt);
        i_cur_year = p_tm_ctxt->tm_year+1900;
        i_cur_mon = p_tm_ctxt->tm_mon+1;
        i_cur_day = p_tm_ctxt->tm_mday;
        i_cur_hour = p_tm_ctxt->tm_hour+8;
        i_cur_min = p_tm_ctxt->tm_min;
        i_cur_sec = p_tm_ctxt->tm_sec;
        i_time_len = sprintf(llbuf, "[%d/%02d/%02d-%02d:%02d:%02d]", 
            i_cur_year, i_cur_mon, i_cur_day, 
            i_cur_hour, i_cur_min, i_cur_sec);
        lxzat_spcomm_f_writebyid(i_vsp_id, llbuf, i_time_len);
        
        va_start(ap,vfmt);
        i_str_len = vsprintf(llbuf, vfmt, ap);
        va_end(ap);
        lxzat_spcomm_f_writebyid(i_vsp_id, llbuf, i_str_len);
        
        i = 0;
        i_cnt_redo = (i_cur_fmt & 0x00FF);
        while (i < i_cnt_redo)
        {
            sprintf(&(llbuf[2 * i + i_pre_len + i_str_len]), "\r\n");
            i++;
        }
        
        i_suf_len = 2 * i_cnt_redo;
        lxzat_spcomm_f_writebyid(i_vsp_id, llbuf, i_suf_len);

        i_sum_len = i_pre_len + i_time_len + i_str_len + i_suf_len;
    }
    
    return i_sum_len;
}

